#ifndef module_h__
#define module_h__


#include "winboost.hpp"
#include "winboost_forwards.hpp"

namespace winboost {
   namespace state {

struct thread_state
{
   HHOOK m_old_hook;
   resources::win_handle* m_pwnd;
   resources::win_handle* m_pwnd_main; // Main window pinter for this thread

   thread_state():
     m_old_hook(NULL)
   , m_pwnd(NULL)
   , m_pwnd_main(NULL)
   {
   }
};

typedef boost::shared_ptr<thread_state>                     state_ptr_type;
typedef boost::unordered_map<int, state_ptr_type>           thread_data_map_type;
typedef boost::unordered_map<HWND, resources::win_handle*>  map_hwnd_to_window_type;

class module : public boost::noncopyable
{
public:
   boost::mutex            m_mutex_access;
   thread_data_map_type    m_thread_map;
   map_hwnd_to_window_type m_window_map;
   HINSTANCE               m_instance;
   HWND                    m_hmdiclient;

   module(void);
   ~module(void);

   thread::application* app(void) const { return m_papplication; }
   void set_app(thread::application* val) { m_papplication = val; }
   HINSTANCE handle(void) const { return m_instance; }
   state_ptr_type get_thread_state(void);
   void add_window(HWND h, resources::win_handle* p);
   resources::win_handle* find_window(HWND hwnd);
   void remove_window(HWND hwnd, resources::win_handle* p);

private:
   thread::application* m_papplication;
   Gdiplus::GdiplusStartupInput m_startup_input;
   ULONG_PTR m_gdiplus_token;
};

//-------------------------------------
// implementation
//-------------------------------------
inline module::module(void):
  m_hmdiclient(NULL)
{
   m_instance = instance_handle();

   // Initialize GDI+.
   Gdiplus::GdiplusStartup(&m_gdiplus_token, &m_startup_input, NULL);
}

inline module::~module(void)
{
   Gdiplus::GdiplusShutdown(m_gdiplus_token);
}


inline state_ptr_type module::get_thread_state(void)
{
   boost::mutex::scoped_lock lock(m_mutex_access);

   DWORD id = ::GetCurrentThreadId();
   thread_data_map_type::iterator it = m_thread_map.find(id);
   if(it == m_thread_map.end())
   {
      // state does not exist for this thread yet
      winboost::state::state_ptr_type pstate = winboost::state::state_ptr_type(new winboost::state::thread_state);
      m_thread_map[id] = pstate;

      it = m_thread_map.find(id);            
   }

   return it->second;
}

inline void module::add_window(HWND h, resources::win_handle* p)
{
   boost::mutex::scoped_lock lock(m_mutex_access);
   m_window_map[h] = p;
}

inline winboost::resources::win_handle* module::find_window(HWND hwnd)
{
   boost::mutex::scoped_lock lock(m_mutex_access);

   map_hwnd_to_window_type::iterator it = m_window_map.find(hwnd);
   if(it == m_window_map.end())
      return NULL;

   return it->second;
}

inline void module::remove_window(HWND hwnd, resources::win_handle* p)
{
   boost::mutex::scoped_lock lock(m_mutex_access);

   map_hwnd_to_window_type::iterator it = m_window_map.find(hwnd);
   if(it == m_window_map.end())
      return;

   m_window_map.erase(it);
}

   }
}

// global module
static winboost::state::module _the_module;


#endif // module_h__

